window.AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.msAudioContext;

var websocketIm = {
    server: {
        instance: null,
        timer: null,
        error_msg: [],
        maxRetryCount: 3,// 最大重连次数
        currentRetryCount: 0,
    },
    url: '',
    port: 0,
    cookie_prefix: '',
    identity: '',
    config: '',
    userInfoMap: {
        friendList: [],
        userInfo: {},
        chatGroup: [],
        historyMessageList: [],
    },
    currentChat: {
        to: '',
        data: '',
        timestamp: 0,
        action: '',
        chat_id: '',
    },
    chatGroupArea: null,
    messageListArea: null,
    messageArea: null,
    uploadImageArea: {
        selector: null,
        id: '#upload_image'
    },
    uploadFileArea: {
        selector: null,
        id: '#upload_file'
    },
    template: {
        file: '<li class="message-item self-message file">\n' +
            '    <div class="avatar">\n' +
            '        <img src="#AVATAR#" alt="" width="65px">\n' +
            '    </div>\n' +
            '    <div class="text message-area ">\n' +
            '        <div class="user-message">\n' +
            '            <span class="username">#USERNAME#&nbsp;#TIMESTAMP#</span>\n' +
            '        </div>\n' +
            '        <div class="message-content">\n' +
            '            <a href="#LINK#" target="_blank">\n' +
            '                <div class="filearea">\n' +
            '                    <div class="file">\n' +
            '                        <span class=\'filename\'>#FILENAME#</span>\n' +
            '                        <span class=\'filesize\'>#FILESIZE#</span>\n' +
            '                    </div>\n' +
            '                    <div class="file-icon">\n' +
            '                        <img src="#FILEEXT#" alt="" width="50px">\n' +
            '                    </div>\n' +
            '                </div>\n' +
            '            </a>\n' +
            '        </div>\n' +
            '    </div>\n' +
            '</li>',
        text: '<li class="message-item">\n' +
            '    <div class="avatar">\n' +
            '        <img src="#AVATAR#" alt="" width="65px">\n' +
            '    </div>\n' +
            '    <div class="text message-area ">\n' +
            '        <div class="user-message">\n' +
            '            <span class="username">#USERNAME#&nbsp;#TIMESTAMP#</span>\n' +
            '        </div>\n' +
            '        <div class="message-content">\n' +
            '            <p>#MESSAGE#</p>\n' +
            '        </div>\n' +
            '    </div>\n' +
            '</li>',
        audio: '',
        image: '<li class="message-item self-message">\n' +
            '    <div class="avatar">\n' +
            '        <img src="#AVATAR#" alt="" width="65px">\n' +
            '    </div>\n' +
            '    <div class="text message-area">\n' +
            '        <div class="user-message">\n' +
            '            <span class="username">#USERNAME#&nbsp; #TIMESTAMP#</span>\n' +
            '        </div>\n' +
            '        <div class="message-content image">\n' +
            '            <img src="#MESSAGE#" alt="">\n' +
            '        </div>\n' +
            '    </div>\n' +
            '</li>',
        image_text: '<li class="message-item self-message">\n' +
            '    <div class="avatar">\n' +
            '        <img src="#AVATAR#" alt="" width="65px">\n' +
            '    </div>\n' +
            '    <div class="text message-area">\n' +
            '        <div class="user-message">\n' +
            '            <span class="username">#USERNAME#&nbsp;#TIMESTAMP#</span>\n' +
            '        </div>\n' +
            '        <div class="message-content">\n' +
            '            <img src="#LINK#" alt="">\n' +
            '            <p>#MESSAGE#</p>\n' +
            '        </div>\n' +
            '    </div>\n' +
            '</li>',
    },
    setIdentity: function (identity) {
        websocketIm.identity = identity;
    },
    initialize: function (domain = document.domain, port = 0, callback = null) {
        if (!("WebSocket" in window) && !("MozWebSocket" in window)) {
            layer.alert("您的浏览器不支持websocket，请使用谷歌浏览器或者edge");
        }
        websocketIm.registerEvent();
        if (websocketIm.identity.length <= 0 && this.getSelfIdentity()) {
            layer.alert('请先设置用户标识或者设置用户标识cookie');
        }
        websocketIm.url = domain;
        websocketIm.port = port
        websocketIm.url = this.buildURI(domain, this.identity);
        websocketIm.connect();
    },
    registerEvent: function () {
        websocketIm.chatGroupArea = $('.chat-list');
        websocketIm.messageListArea = $('.message-list');
        websocketIm.messageArea = $('#msg-content');
        websocketIm.uploadImageArea.selector = $('#upload_image');
        websocketIm.uploadFileArea.selector = $('#upload_file');

        //切换会话事件监听
        $(document).on('click', '.change_friend', function (event) {
            if (event.currentTarget.getAttribute('data-chat-id') != websocketIm.currentChat.chat_id) {
                websocketIm.changeChat(event);
                $('.message-list').attr('page', 0);
            }
        })

        //点击发送事件监听
        $(document).on('click', '#send', function (event) {
            if (!Object.keys(websocketIm.currentChat).indexOf('to') || websocketIm.currentChat.to == '') {
                layer.msg('请选择一个好友');
                return;
            }

            if (websocketIm.messageArea.html() !== websocketIm.messageArea.text() && websocketIm.messageArea.text().length > 0) {
                if (websocketIm.messageArea.html() != websocketIm.messageArea.text()) {
                    websocketIm.currentChat.data += websocketIm.messageArea.html();
                    /**
                     * 过滤掉img标签
                     * @type {string}
                     */
                    websocketIm.currentChat.action = 'image_text';
                }
            } else {
                websocketIm.currentChat.data = websocketIm.messageArea.text();
            }
            websocketIm.send();
        })

        /* //触发文件域上传
         $(document).on('click', '#upload_image_button', function (event) {
             if (!websocketIm.currentChat.chat_id) {
                 layer.msg('请选择一位好友');
                 return;
             }
             $(websocketIm.uploadImageArea.id).trigger('click');
         });

         //图片上传-文件上传事件监听
         $(document).on('change', $(websocketIm.uploadImageArea.id), function (event) {
             var fileList = event.data[0].files;
             websocketIm.uploader(fileList);
         })*/

        //触发文件域上传
        $(document).on('click', '#upload_file_button', function (event) {
            if (!websocketIm.currentChat.chat_id) {
                layer.msg('请选择一位好友');
                return;
            }
            $(websocketIm.uploadFileArea.id).trigger('click');
        });

        //文件上传事件监听
        $(document).on('change', $(websocketIm.uploadFileArea.id), function (event) {
            var fileList = event.data[0].files;
            websocketIm.uploader(fileList);
        })

        //聊天记录滚动条触顶加载
        $(document).on('scroll', '.message-list', function (event) {
            let page = event.currentTarget.getAttribute('page');
            websocketIm.loadHistoryMessage(websocketIm.currentChat.chat_id, page);
            event.currentTarget.setAttribute('page', parseInt(page) + 1);
        })

        // 选择表情
        $(document).on('click', '#_face', function () {
            /*if (!websocketIm.currentChat.chat_id) {
                layer.msg('请选择一位好友');
                return;
            }*/

            let face = $(this).attr('src'), eq = $(this).attr('data');

            websocketIm.messageArea.append("<img src='" + face + "' data='" + eq + "' width='25px'>");
        });


    },
    connect: function () {
        var ws = new WebSocket(websocketIm.url), _this = websocketIm;
        _this.server.instance = ws;

        ws.onopen = function () {
            _this.server.currentRetryCount = 0;

            // 重新发送所有出错的消息
            if (_this.server.error_msg.length > 0) {

                for (let i in this.server.error_msg) {
                    this.send();
                }

                this.server.error_msg = [];
            }

            if (_this.server.timer != null) {
                clearInterval(_this.server.timer);
            }

            setTimeout(function () {
                _this.server.timer = setInterval(_this.ping(), 28000);//定时发送心跳
            }, 1500)
        };

        ws.onmessage = function (evt) {
            var data = $.parseJSON(evt.data);

            if (data.code != 200) {
                layer.msg(data.notice)
            }

            _this.parseMessage(data);
        };

        ws.onclose = function (e) {
            if (_this.server.timer != null) {
                clearInterval(_this.server.timer);
            }
            layer.msg('网络链接已断开');
            if (_this.server.maxRetryCount) {
                _this.server.timer = setInterval(_this.retryConnect, 3000);//每3秒重新连接一次
            }
        };

        ws.onerror = function (e) {
            // 错误
            console.log('websocket 错误:', e);
            layer.msg('WebSocket 发生错误,请查看控制台');
        };
    },
    parseMessage: function (data) {
        if (data.action == 'login') {
            websocketIm.server.config = data.data.config;
            websocketIm.userInfoMap.friendList = data.data.friend_ship;
            websocketIm.userInfoMap.userInfo = data.data.user_info;
            websocketIm.userInfoMap.historyMessageList = data.data.history_message;
            websocketIm.userInfoMap.chatGroup = data.data.chat_group;
            websocketIm.setCookie('identity', websocketIm.userInfoMap.userInfo.identity);
            //初始化好友列表
            let html = '';
            websocketIm.userInfoMap.chatGroup.map(function (value, index, array) {
                let dotClass = 'dot', identity = '', avatar = '', username = '';
                if (value.user_del == 0) {
                    if (value.client == websocketIm.getSelfIdentity()) {
                        if (value.user_read == 1) {
                            dotClass += ' hidden';
                        }
                        identity = value.receiver.identity;
                        avatar = value.receiver.avatar;
                        username = value.receiver.username;
                    } else if (value.touid == websocketIm.getSelfIdentity()) {
                        if (value.to_read == 1) {
                            dotClass += ' hidden';
                        }
                        identity = value.sender.identity;
                        avatar = value.sender.avatar;
                        username = value.sender.username;
                    }
                    html += "<li class=\"chat-item change_friend\" " +
                        "data-chat-id='" + value.chat_id + "' " +
                        "data-client='" + identity + "'>\n" +
                        "<div class='" + dotClass + "'></div>" +
                        "                    <div class=\"avatar\">\n" +
                        "                        <img src=\"" + avatar + "\" alt=\"\" width=\"50px\">\n" +
                        "                    </div>\n" +
                        "                    <div class=\"userinfo\">\n" +
                        "                        <div class=\"username\">\n" +
                        "                            <span class=\"text\">" + username + "</span>\n" +
                        "                            <span class=\"time\">" + value.timestamp + "</span>\n" +
                        "                        </div>\n" +
                        "                        <div class=\"message\">" + value.last_message + "</div>\n" +
                        "                    </div>\n" +
                        "                </li>"
                }
            })
            $('.chat-list').append(html)
            let info = "<img src='" + websocketIm.userInfoMap.userInfo.avatar + "' width='55px'/>" + websocketIm.userInfoMap.userInfo.username
            $('.info').append(info)
        } else if (data.action == 'history') {
            //加载历史聊天记录
            $('.message-list').attr('page', data.data.page)
            //遍历填充消息
            data.data.history.map(function (value, index, array) {
                websocketIm.buildMessageHtml(value);
            })
            websocketIm.messageListToBottom();
        } else if (data.action != 'ping') {
            websocketIm.buildMessageHtml(data);
            websocketIm.messageListToBottom();
        }
    },
    retryConnect: function () {

    },
    send: function () {
        if (websocketIm.server.instance && websocketIm.server.instance.readyState == 1) {
            res = websocketIm.server.instance.send(JSON.stringify(websocketIm.currentChat));

            var content = websocketIm.currentChat;
            content.sender = websocketIm.userInfoMap.userInfo;
            content.from = websocketIm.userInfoMap.userInfo.identity;
            content.time = websocketIm.getTimeStamp();
            console.log(content);
            websocketIm.buildMessageHtml(content);

            websocketIm.currentChat.data = '';
            websocketIm.currentChat.action = 'text';
            websocketIm.messageArea.html('')
        } else {
            layer.msg('发送消息失败');
        }
    },
    read: function (chatId) {
        if (websocketIm.server.instance && websocketIm.server.instance.readyState == 1) {
            let data = {
                data: {
                    chat_id: chatId,
                    identity: websocketIm.getSelfIdentity()
                },
                action: 'read',
            }
            let res = websocketIm.server.instance.send(JSON.stringify(data));
            $('li[data-chat-id="' + chatId + '"]').children('.dot').addClass('hidden');
        }
    },
    changeChat: function (event) {
        websocketIm.messageListArea.children('.message-item').remove();
        websocketIm.currentChat.to = event.currentTarget.getAttribute('data-client');
        websocketIm.currentChat.chat_id = event.currentTarget.getAttribute('data-chat-id');
        if (!$(event.currentTarget.children[0]).hasClass('hidden')) {
            websocketIm.read(event.currentTarget.getAttribute('data-chat-id'));
        }
        websocketIm.loadHistoryMessage(event.currentTarget.getAttribute('data-chat-id'));
    },
    loadHistoryMessage: function (chatId, page = 0) {
        let data = {
            action: 'history',
            data: {
                chat_id: chatId,
                page: page,
                limit: 15,
            }
        };
        websocketIm.server.instance.send(JSON.stringify(data));
    },
    buildMessageHtml: function (value) {
        var html = '', className = '', avatar = '', username = '';
        if (value.from == websocketIm.getSelfIdentity()) {
            className = ' message-item self-message';
        } else {
            className = ' message-item';
        }

        avatar = value.sender.avatar;
        username = value.sender.username;
        html = '<li class="' + className + '">\n' +
            '    <div class="avatar">\n' +
            '        <img src="' + avatar + '" alt="" width="65px">\n' +
            '    </div>\n' +
            '    <div class="text message-area ">\n' +
            '        <div class="user-message">\n' +
            '            <span class="username">' + username + '&nbsp;' + value.time + '</span>\n' +
            '        </div>\n' +
            '        <div class="message-content ' + value.action + '">\n';
        switch (value.action) {
            case 'text':
                html += '<p>' + value.data + '</p>\n';
                break;
            case 'image':
                html += '<img src="' + value.data.url + '" alt="">';
                break;
            case 'file':
                html += '<a href="' + value.data.url + '" target="_blank">\n' +
                    '                <div class="filearea">\n' +
                    '                    <div class="file">\n' +
                    '                        <span class=\'filename\'>' + value.data.filename + '</span>\n' +
                    '                        <span class=\'filesize\'>' + value.data.size + '</span>\n' +
                    '                    </div>\n' +
                    '                    <div class="file-icon">\n' +
                    '                        <img src="' + value.data.icon + '" alt=""' +
                    ' width="50px">\n' +
                    '                    </div>\n' +
                    '                </div>\n' +
                    '            </a>\n';
                break;
            case 'audio':
                break;
            case 'image_text':
                html += '<img src="' + value.link + '" alt="">' +
                    '<p>' + value.data + '</p>\n';
                break;
        }

        html += '        </div>\n' +
            '    </div>\n' +
            '</li>';
        websocketIm.messageListArea.append(html);
        websocketIm.messageListToBottom();
    },
    ping: function () {
        websocketIm.currentChat = {
            action: 'ping',
            data: 'ping',
            timestamp: this.getTimeStamp(),
        };
        websocketIm.send();
    },
    getTimeStamp: function () {
        return parseInt((new Date()).valueOf() / 1000);
    },
    setCookie: function (name, value, days) {
        var d = new Date();
        d.setTime(d.getTime() + (days * 24 * 60 * 60 * 1000));
        var expires = "expires=" + d.toUTCString();
        document.cookie = websocketIm.cookie_prefix + name + "=" + value + ";" + expires + ";path=/";
    },
    getCookie: function (cname) {
        var name = websocketIm.cookie_prefix + cname + "=";
        var decodedCookie = decodeURIComponent(document.cookie);
        var ca = decodedCookie.split(';');
        for (var i = 0; i < ca.length; i++) {
            var c = ca[i];
            while (c.charAt(0) == ' ') {
                c = c.substring(1);
            }
            if (c.indexOf(name) == 0) {
                return c.substring(name.length, c.length);
            }
        }
        return '';
    },
    buildURI: function (domain, identity) {
        let type = 'ws';
        if (websocketIm.port > 1000) {
            domain += ':' + websocketIm.port;
        }
        if (window.location.protocol == 'https:') {
            type = 'wss';
        }
        return `${type}://${domain}/websocket?token=${identity}`;
    },
    uploader: function (fileList) {
        for (var i = 0; i < fileList.length; i++) {
            let formData = new FormData,
                file = fileList[i],
                uploadUrl = '/upload/',
                fileType = '',
                otherType = ['image', 'audio', 'video'];
            [fileType] = file.type.split('/');
            if (otherType.indexOf(fileType) == -1) {
                fileType = 'file';
            }
            formData.append(fileType, file);

            $.ajax({
                url: uploadUrl + fileType,
                method: 'post',
                data: formData,
                contentType: false,
                processData: false,
                success: function (res) {
                    if (res.code == 200) {
                        websocketIm.handleAjaxFileUploaded(res.data, fileType)
                    } else {
                        layer.msg('上传失败:' + res.msg);
                    }
                },
                error: function (error) {
                    layer.msg('文件上传失败');
                },
                complete: function (res) {
                }
            })
        }
    },
    handleAjaxFileUploaded: function (data, type) {
        websocketIm.currentChat.data = data;
        websocketIm.currentChat.action = type;
        websocketIm.cleanFileArea();
        websocketIm.send();
    },
    getSelfIdentity: function () {
        return websocketIm.getCookie('identity')
    },
    cleanFileArea: function () {
        $('.file-area-span').append(' <input type="file" name="upload-file" id="upload_file" style="display: none;" accept="*/*">');
    },
    messageListToBottom: function () {
        let scrollHeight = websocketIm.messageListArea[0].scrollHeight;
        document.querySelector('#message').scrollTop = scrollHeight;

    }
}
